package demo.util.http;

import com.google.common.collect.ImmutableMap;
import com.google.gson.Gson;
import demo.db.mybatis.pojo.User;
import kong.unirest.GenericType;
import kong.unirest.HttpResponse;
import kong.unirest.JsonNode;
import kong.unirest.Unirest;
import kong.unirest.UnirestParsingException;
import org.apache.commons.lang3.StringUtils;
import org.junit.Test;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;

// https://blog.csdn.net/wjw465150/article/details/127961389
public class UnirestHttpClientDemo {

    @Test
    public void test() {
        HttpResponse<String> response = Unirest.post("http://ops.ximalaya.com/ai-cloud-deploy-server/k8s/serving/group/instance/getPodInfo")
                .header("Content-Type", "application/json")
                .connectTimeout(1000)
                .socketTimeout(1000)
                .body("{}")
                //当’ asType '被调用时发出请求，可能的类型包括Json， String， Object， Empty和File。
                .asString();
        System.out.println(response.getBody());
    }

    public void demo() throws FileNotFoundException {
        // 路由(路径)参数
        Unirest.get("http://localhost/{fruit}")
                .routeParam("fruit", "apple")
                .asString();


//        默认的基础URL
//        这个配置将导致GET到 “http://homestar.com/runner”
        Unirest.config().defaultBaseUrl("http://homestar.com");
        Unirest.get("/runner").asString();

//        查询字符串参数可以一个一个地建立
        Unirest.get("http://localhost")
                .queryString("fruit", "apple")
                .queryString("droid", "R2D2")
                .asString();
// Results in "http://localhost?fruit=apple&droid=R2D2"

        // 你也可以将查询字符串作为数组和map传入:
        Unirest.get("http://localhost")
                .queryString("fruit", Arrays.asList("apple", "orange"))
                .queryString(ImmutableMap.of("droid", "R2D2", "beatle", "Ringo"))
                .asString();

        // Results in "http://localhost?fruit=apple&fruit=orange&droid=R2D2&beatle=Ringo"


//        请求头可以通过header’方法添加。

        Unirest.get("http://localhost")
                .header("Accept", "application/json")
                .header("x-custom-header", "hello")
                .asString();

//        Unirest 提供了在需要时进行基本身份验证的快捷方式。 Unirest 处理 Base64 编码部分。 请确保您始终通过 HTTPS 执行此操作！
        Unirest.get("http://localhost")
                .basicAuth("user", "password1!")
                .asString();

//        Entity Bodies(实体对象Bodies)
//                您可以轻松地将实体对象作为body发布。 这是大多数 REST 服务的默认行为。
//
//        除非你另外指定，默认的Content-Type 是 text/plain; charset=UTF-8

        Unirest.post("http://localhost")
                .body("This is the entire body")
                .asEmpty();

//        您还可以发布为使用配置的 ObjectMapper 序列化的对象。 （请参阅 Object Mappers了解实现细节)。Unirest 带有一个默认映射器，它将使用流行的 Google Gson 库序列化为 json

        Unirest.post("http://localhost")
                .header("Content-Type", "application/json")
                .body(new User("Bob"))
                .asEmpty();
        // Basic Forms(基本表单)
        //可以通过简单的field调用传递基本的 http 名称值(name value) body 参数。 此类请求的Content-Type默认为application/x-www-form-urlencoded
        //
        Unirest.post("http://localhost")
                .field("fruit", "apple")
                .field("droid", "R2D2")
                .asEmpty();
//        文件上传
//        您还可以在表单中发布二进制数据。 例如一个文件。
//
//        此类请求的 Content-Type 默认为 multipart/form-data

        Unirest.post("http://localhost")
                .field("upload", new File("/MyFile.zip"))
                .asEmpty();

        // 对于大文件，您可能需要使用 InputStream。 如果需要，请传递一个文件名。 我们在这里使用 FileInputStream 但它实际上可以是任何类型的 InputStream子类。
        InputStream file = new FileInputStream(new File("/MyFile.zip"));

        Unirest.post("http://localhost")
                .field("upload", file, "MyFile.zip")
                .asEmpty();

//        上传进度监控
//        如果您要上传大文件，您可能希望向用户提供一些时间进度条。 您可以通过提供 ProgresMonitor 来监控此进度。

        Unirest.post("http://localhost")
                .field("upload", new File("/MyFile.zip"))
                .uploadMonitor((field, fileName, bytesWritten, totalBytes) -> {
                    updateProgressBarWithBytesLeft(totalBytes - bytesWritten);
                })
                .asEmpty();


//        异步请求
//        有时候，在大多数情况下，您希望应用程序是异步的而不是阻塞的，Unirest在Java中使用匿名回调或直接方法放置来支持这一点。所有请求类型也支持异步版本。
        CompletableFuture<HttpResponse<JsonNode>> future = Unirest.post("http://localhost/post")
                .header("accept", "application/json")
                .field("param1", "value1")
                .field("param2", "value2")
                .asJsonAsync(response -> {
                    int code = response.getStatus();
                    JsonNode body = response.getBody();
                });

//        客户端证书
//        如果您需要使用自定义客户端证书来调用服务，您可以为 unirest 提供自定义密钥库。 您可以传递 KeyStore 对象或有效 PKCS#12 密钥库文件的路径。

        Unirest.config()
                .clientCertificateStore("/path/mykeystore.p12", "password1!");

        Unirest.get("https://some.custom.secured.place.com")
                .asString();

//        Proxies(代理)
//        有时您需要通过代理隧道。Unirest可以配置为这样做。注意，身份验证代理不能按每个请求进行配置，除非您想将其构建到URL本身中。

// Configure with authentication:
        Unirest.config().proxy("proxy.com", 7777, "username", "password1!");

        // or without
        Unirest.config().proxy("proxy.com", 7777);

        // or pass it in the request. This will override any proxy done in the config
        // currently only unauthenticated proxies work
        Unirest.get("aa")
                .proxy("proxy.com", 7777)
                .asString();

//        Responses(响应)
//        Unirest 在您调用它的 as[type] 方法时发出实际请求。 这些方法还通知 Unirest 将响应映射到什么类型。 选项有Empty、String、File、Object、byte和Json。

//        响应返回一个HttpResponse<T>，其中HttpResponse对象拥有所有常见的响应数据，如状态和头信息。可以通过.getbody()方法访问Body(如果存在)。

//        Empty Responses(空响应)
//                如果你不关心响应回来的消息体，asEmpty 是最简单的选择。 您仍然会得到状态和标题等响应信息。

        HttpResponse response = Unirest.delete("http://localhost").asEmpty();
//        String Responses(字符串响应)
//                下一个最简单的响应类型是String。你想怎么处理都可以。

        String body = Unirest.get("http://localhost")
                .asString()
                .getBody();

//        Object Mapped Responses(对象映射响应)
        // Response to Object
        User book = Unirest.get("http://localhost/books/1")
                .asObject(User.class)
                .getBody();

// Generic types can be resolved by using a GenericType subclass to avoid erasure
        List<User> books = Unirest.get("http://localhost/books/")
                .asObject(new GenericType<List<User>>() {
                })
                .getBody();

        User author = Unirest.get("http://localhost/books/{id}/author")
                .routeParam("id", "1")
                .asObject(User.class)
                .getBody();

//        对象或JSON解析出错时
//        你不能总是得到你想要的。 有时您从 Web 服务获得的结果不会映射到您期望的结果。
//        当asObject 或asJson 请求发生这种情况时，结果主体将为空，但响应对象将包含一个 ParsingException，允许您获取错误和原始主体以供检查。
        UnirestParsingException ex = (UnirestParsingException) response.getParsingError().get();
        ex.getOriginalBody(); // Has the original body as a string.
        ex.getMessage(); // Will have the parsing exception.
        ex.getCause(); // of course will have the original parsing exception itself.

//        不使用对象映射器将返回的Body映射成一种类型
        int body1 = Unirest.get("http://httpbin/count")
                .asString()
                .mapBody(Integer::valueOf);

//File Responses(文件响应)
        File result = Unirest.get("http://some.file.location/file.zip")
                .asFile("/disk/location/file.zip")
                .getBody();
//        下载进度监控
        Unirest.get("http://localhost").downloadMonitor((b, fileName, bytesWritten, totalBytes) -> {
                    updateProgressBarWithBytesLeft(totalBytes - bytesWritten);
                })
                .asFile("/disk/location/file.zip");

//JSON responses(JSON 响应)
//当您不需要完整的对象映射器时，Unirest 提供了一种轻量级的 JSON 响应类型。
        Object result1 = Unirest.get("http://some.json.com")
                .asJson()
                .getBody()
                .getObject()
                .getJSONObject("car")
                .getJSONArray("wheels")
                .get(0);

        // Large Responses(大响应)
        //一些响应方法（asString、asJson）将整个响应流读入内存。 为了读取原始流并处理大响应，您可以使用多种函数方法
        Map m = Unirest.get("http://local")
                .queryString("firstname", "Gary")
                .asObject(i -> new Gson().fromJson(i.getContentReader(), HashMap.class))
                .getBody();
//或消费者：
        Unirest.get("http://local")
                .thenConsumeAsync(r -> {
                    System.out.println(r);
                    // something like writing a file to disk
                });

//        错误处理
//        HttpResponse对象有一些处理方法，可以通过链接来处理成功和失败:

//        ifSuccess(Consumer<HttpResponse<T>> response) 将被调用，如果响应是一个200系列的响应，并且任何主体处理(如Json或Object是成功的。
//                ifFailure(Consumer<HttpResponse> response 将在状态为400+或主体处理失败时被调用。
//                        将它们放在一起可能如下所示：

        Unirest.get("http://somewhere")
                .asJson()
                .ifSuccess(r1 -> {
                })
                .ifFailure(t2 -> {
                    t2.getParsingError().ifPresent(e -> {
                    });
                });


    }

    public void test2() {
        Unirest.shutDown();
        ;
    }

    private void updateProgressBarWithBytesLeft(long l) {
    }

    /**
     * URL探测报警
     *
     * @param app
     * @param url
     */
    public void addUrlAlert(String app, String url, String serviceId) {
        HttpResponse<String> response = Unirest.post("http://xdcs.ximalaya.com/admin/app_rule/save")
                .header("Authorization", "Basic anVueWluZy5oYW46U3RhbkAyMDE5MDQ=")
                .field("appName", app)
                .field("ruleId", "264")
                .field("serviceId", serviceId)
                .field("logIdentity", url)
                .field("remark", "健康检查")
                .field("active", "true")
                .field("priority", "40")
                .field("alertSenderType", "all")
                .field("alertSpan", "10")
                .field("threshold", "{}")
                .field("keyword", "")
                .asString();
        if (response.isSuccess()) {
            System.err.println(response.getBody());
        } else {
            System.err.println(response);
        }

    }

    /**
     * URL探测报警
     *
     * @param app
     * @param ipPort
     */
    public void addPortAlert(String app, String ipPort, String serviceId) {
        HttpResponse<String> response = Unirest.post("http://xdcs.ximalaya.com/admin/app_rule/save")
                .header("Authorization", "Basic anVueWluZy5oYW46U3RhbkAyMDE5MDQ=")
                .field("appName", app)
                .field("ruleId", "179")
                .field("serviceId", serviceId)
                .field("logIdentity", ipPort)
                .field("remark", "健康检查")
                .field("active", "true")
                .field("priority", "40")
                .field("alertSenderType", "all")
                .field("alertSpan", "10")
                .field("threshold", "{}")
                .field("keyword", "")
                .asString();
        if (response.isSuccess()) {
            System.err.println(response.getBody());
        } else {
            System.err.println(response);
        }

    }

    // 增加应用健康检查报警
    @Test
    public void testAddAppRule() {
        String service = "hw-sh1-1-pro-cce-primary-1";
        String appName = "kube-scheduler";
        String str = "10.157.16.196:10259\n" +
                "10.157.16.38:10259\n" +
                "10.157.17.217:10259";
        String[] nodeList = str.split("\n");
        for (String node : nodeList) {
            if (StringUtils.isBlank(node)) {
                continue;
            }
            System.err.println(node);
            if (node.startsWith("http")) {
                addUrlAlert(appName, node, service);
            } else {
                addPortAlert(appName, node, service);
            }
        }
    }

    public List<String> listConsulServer() {
        HttpResponse<JsonNode> response = Unirest.get("https://consul.ximalaya.com/v1/status/peers").asJson();
        if (response.isSuccess()) {
            List<String> result = new ArrayList<>();
            response.getBody().getArray().forEach(item -> {
                System.err.println(item);
                result.add((String) item);
            });
            System.out.println(result);
            return result;
        }
        System.err.println(response);
        return Collections.emptyList();
    }

}
